package inteligenciaartificial;

import java.util.Arrays;

public class IndividuoManager {
	
	//en este arreglo se cargar�n los valores l�mite para cada gen del individuo
	//se tiene un Intervalo por cada gen del individuo
	private static Intervalo[] valoresLimite;
	private static int[] cantidadesDeMateriales;
        private static int[] utilidades;
        private static int maximoTeorico;

	
	public static void inicializar(int[] cantidadesDeMateriales,Intervalo[] valoresLimite, int[] utilidades){
            IndividuoManager.valoresLimite= valoresLimite;
            IndividuoManager.cantidadesDeMateriales= cantidadesDeMateriales;
            int[] maximos= IndividuoManager.calcularMaximasCantidades(cantidadesDeMateriales, valoresLimite);
            IndividuoManager.valoresLimite[0]= new Intervalo(0,maximos[0]+1);
            IndividuoManager.valoresLimite[9]= new Intervalo(0,maximos[1]+1);
            IndividuoManager.valoresLimite[18]= new Intervalo(0,maximos[2]+1);
            IndividuoManager.valoresLimite[27]= new Intervalo(0,maximos[3]+1);
            IndividuoManager.utilidades= utilidades;
            IndividuoManager.maximoTeorico= maximos[0]*utilidades[0] +
                                            maximos[1]*utilidades[1] +
                                            maximos[2]*utilidades[2] +
                                            maximos[3]*utilidades[3] ;
        }
	
	public static Individuo crearIndividuoAleatorio(){
		
		Individuo individuoAleatorio;
		int[] genes = new int[Individuo.CantidadDeGenes];
		
		do{
			for(int i=0; i < Individuo.CantidadDeGenes; i++){
                                //para mejorar la performance se deberian tomar valores altos para las cantidad de producto.
                                //para esto si el gen corresponde a la cantidad de producto, o sea genes 0,9,18 y 27, el intervalo se toma as grande al real
                                if(i==0 || i==9 || i==18 || i==27){
                                    //si el gen corresponde a una cantidad de producto aumento la aplitud en un 100% para favorecer los numeros cerca del limite
                                    genes[i]= (int) (getValoresLimite()[i].getMinimo() + (Math.random() * (getValoresLimite()[i].amplitud())));
                                }else{
                                    genes[i]= (int) (getValoresLimite()[i].getMinimo() + (Math.random() * getValoresLimite()[i].amplitud()));
                                }
			}
			individuoAleatorio= new Individuo(genes);
		
		}while(!IndividuoManager.individuoCumpleRestricciones(individuoAleatorio));
		
		return individuoAleatorio;
	}
	
	public static boolean individuoCumpleRestricciones(Individuo individuo){
		if (individuo==null) return false;
		int[] totalesMateriales= new int[8];
		for(int m=0; m<8; m++){
			for(int p=1;p<5;p++){
				totalesMateriales[m]=totalesMateriales[m]+ ( individuo.getCantidadProducto(p) * individuo.getCantidadMaterial(p, m+1) );
			}
		}
		
		for(int i=0;i<8;i++){
			if(totalesMateriales[i] > IndividuoManager.getCatidadesDeMateriales()[i]) return false;
		}
		
		return true;
	}
        
        public static Intervalo getIntervaloParaPosicion(int indice){
            return getValoresLimite()[indice];
        }

    /**
     * @return the valoresLimite
     */
    public static Intervalo[] getValoresLimite() {
        return valoresLimite;
    }

    /**
     * @param aValoresLimite the valoresLimite to set
     */
    public static void setValoresLimite(Intervalo[] aValoresLimite) {
        valoresLimite = aValoresLimite;
    }

    /**
     * @return the catidadesDeMateriales
     */
    public static int[] getCatidadesDeMateriales() {
        return cantidadesDeMateriales;
    }

    /**
     * @param aCatidadesDeMateriales the catidadesDeMateriales to set
     */
    public static void setCatidadesDeMateriales(int[] aCatidadesDeMateriales) {
        cantidadesDeMateriales = aCatidadesDeMateriales;
    }
    
    public static int getMaximoTeorico(){
        return IndividuoManager.maximoTeorico;
    }
    
    public static int[] getUtilidades(){
        return utilidades;
    }
    
   public static int[] calcularMaximasCantidades(int[] materiales, Intervalo[] intervalos){
        
            int[] maximosPorProducto= new int[4];
            for(int mp=0;mp<4;mp++){
                //calculo para sacar el inicio de intervalo de las MP de cada producto
                int comienzoIntProM=(1+mp)+(8*mp);
                
                int[] maximosPosiblesPorMP= new int[8];
                for(int m=0; m<8; m++){
                    if(intervalos[comienzoIntProM+m].getMinimo()==0){
                        maximosPosiblesPorMP[m]= Integer.MAX_VALUE;    
                    }else{
                        maximosPosiblesPorMP[m]= (int) (materiales[m] / intervalos[comienzoIntProM+m].getMinimo());
                    }          
                }
                //ordeno descendentemente, ya que el maximo que puedo producir es elMINIMO de todos los maximos
                Arrays.sort(maximosPosiblesPorMP);
                
                maximosPorProducto[mp]=maximosPosiblesPorMP[0];
            }
            return maximosPorProducto;
        }

}


